﻿package net.area80.sitemanager
{
	import flash.display.DisplayObjectContainer;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.media.SoundMixer;
	import flash.net.NetStream;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.utils.Dictionary;
	import net.area80.Area80;
	import net.area80.debug.FPS;
	import net.area80.sitemanager.display.FreezeClip;
	import net.area80.sitemanager.display.IProgressClip;
	import net.area80.sitemanager.display.LoaderClip;
	import net.area80.sitemanager.events.LoadProgressClipEvent;
	import net.area80.sitemanager.events.PageEvent;
	import net.area80.sitemanager.events.SiteManagerEvent;
	import net.area80.sitemanager.page.IPage;
	
	/**
	* SiteManager
	* @author Wissarut Pimanmassuriya
	*/
	public class SiteManager extends EventDispatcher implements ISiteManager
	{
		/**
		 * Tracking URL, leave it to "" or "javascript" to track by [javascript:trace(page)] function. 
		 */
		public var trackURL:String = "";
		
		public static var VERBOSE:Boolean = true;
		
		private var freezeClip:FreezeClip;
		private var _main:DisplayObjectContainer;
		public var defaultPageLoader:Loader;
		private var defaultPageProgress:IProgressClip;
		private var pageProgressDict:Dictionary;
		
		public function SiteManager (mainPage:DisplayObjectContainer, defaultPageLoader:Loader = null, defaultPageProgress:IProgressClip = null, freezeClip:FreezeClip = null):void {
				if (SiteManagerProxy.siteManager) {
					if(SiteManager.VERBOSE) Area80.log("Error : Can't have SiteShell more than one.", this);
					return ;
				}
				
				SiteManagerProxy.setSiteManager(this);
				
				pageProgressDict = new Dictionary(true);
				
				this.defaultPageLoader = defaultPageLoader;
				this.defaultPageProgress = defaultPageProgress;
				_main = mainPage;
				this.freezeClip = (freezeClip) ? freezeClip : new FreezeClip();
				_main.addChild(this.freezeClip);
				_main.addEventListener(Event.ADDED , onDisplayAdded, false, 0, true);
		}
		
		public function getPermaString ():String {
				//TODO: Permanent links
				return "";
		}
		
		public function track (page:String):void {
			if(_main.loaderInfo.url.indexOf("http")==0) {
					if (trackURL == "" || trackURL == "javascript") {
							navigateToURL(new URLRequest("javascript:track('"+page+"');"), "_self");
					} else {
							var urlLoader:URLLoader = new URLLoader();
							urlLoader.load(new URLRequest(trackURL + page));
					}
			} else {
					if(SiteManager.VERBOSE) Area80.log("Main.track('" + page + "')", this);
			}
		}
		
		public function get main ():DisplayObjectContainer { return _main;  }
		
		/**
		 * Load Page to defaultLoader in Main, automaticaly freeze the page when load
		 * @param	url
		 * @param	autoPlay
		 * @param	callBack
		 * @param	extras
		 */
		public function loadPage (url:URLRequest, autoPlay:Boolean = true, onInit:Function = null, onOut:Function = null, extras:Object = null):void {
				if (!defaultPageLoader) {
					if(SiteManager.VERBOSE) Area80.log("Error@loadPage, Default page loader must be added before use loadPage", this);
					return;
				}
				
				freeze();
				
				function loadInitCallBack () {
					unFreeze();
					if(onInit != null) onInit(); 
				}

				if (defaultPageLoader.content && defaultPageLoader.content is IPage) {
					IPage(defaultPageLoader.content).addEventListener(PageEvent.EVENT_OUT, outHandler);
					IPage(defaultPageLoader.content).moveOut();
					function outHandler (eOut:Event) {
						eOut.currentTarget.removeEventListener(PageEvent.EVENT_OUT, outHandler);
						loadPageToTarget(url, defaultPageLoader, defaultPageProgress, autoPlay, loadInitCallBack, onOut, extras);
					}
				} else {
						loadPageToTarget(url, defaultPageLoader, defaultPageProgress, autoPlay, loadInitCallBack, onOut, extras);
				}
				
		}
		
		public function loadPageToTarget (url:URLRequest, target:Loader, progressClip:IProgressClip = null, autoPlay:Boolean = true, onInit:Function = null, onOut:Function = null, extras:Object = null):void {

				freeze();
				
				if (progressClip) {
					progressClip.init();
					progressClip.moveIn();
					
					
					progressClip.addEventListener(LoadProgressClipEvent.READY, proFunc, false, 0, true);
					
					function proFunc () {
						progressClip.removeEventListener(LoadProgressClipEvent.READY, proFunc);
						try { target.close();  } catch (error:Error) { }
						try { target.unload();  } catch (error:Error) { }

						target.load(url);
							
						pageProgressDict[target.contentLoaderInfo] = progressClip;
						target.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler, false, 0, true);
					}
					
				} else {

					try { target.close();  } catch (error:Error) { }
					try { target.unload();  } catch (error:Error) { }

					target.load(url);
				}
				
				target.contentLoaderInfo.addEventListener(Event.COMPLETE, completeFunc);
				target.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorFunc);
				
				function completeFunc (cEvent:Event) {
						cEvent.currentTarget.removeEventListener(Event.COMPLETE, completeFunc);
						cEvent.currentTarget.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorFunc);
						unFreeze();
						if (progressClip) {
							progressClip.updateProgress(target.contentLoaderInfo.bytesLoaded, target.contentLoaderInfo.bytesTotal);
							progressClip.moveOut();
						}
						
						IPage(target.content).addEventListener(PageEvent.EVENT_OUT,eOut);
						function eOut (eOutE:Event) {
							eOutE.currentTarget.removeEventListener(PageEvent.EVENT_OUT,eOut);
							if (target != defaultPageLoader && target.parent.contains(target)) target.parent.removeChild(target);
							try { target.close();  } catch (error:Error) { }
							try { target.unload();  } catch (error:Error) { }
							if (onOut != null) onOut();
						}
						function onPageInit (eInit:Event) {
							eInit.currentTarget.removeEventListener(PageEvent.EVENT_INIT, onPageInit);
							dispatchEvent(new SiteManagerEvent(SiteManagerEvent.PAGE_INIT));
							if (onInit != null) onInit();
						}
						IPage(target.content).initExtras(extras);
						if (autoPlay) {
							IPage(target.content).addEventListener(PageEvent.EVENT_INIT, onPageInit);
							IPage(target.content).moveIn();
						}
						dispatchEvent(new SiteManagerEvent(SiteManagerEvent.PAGE_LOADED));
				}
				
				function ioErrorFunc (iEvent:Event) {
						iEvent.currentTarget.removeEventListener(Event.COMPLETE, completeFunc);
						iEvent.currentTarget.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorFunc);
						loadPageToTarget (url, target, progressClip, autoPlay, onInit, onOut, extras);
				}
				
	
		}
		
		public function freeze (callerObject:* = null):void {
			if (!callerObject) {
					callerObject = "";
			} else {
					callerObject = callerObject+"->";
			}
			if (freezeClip.visible) {
					if (SiteManager.VERBOSE) Area80.log(callerObject + "Duplicate freeze(); Command", this);
					return;
			}
			if (SiteManager.VERBOSE) Area80.log(callerObject + "freeze()", this);
			freezeClip.visible = true;
		}
		
		public function unFreeze (callerObject:* = null):void {
			if (!callerObject) {
					callerObject = "";
			} else {
					callerObject = callerObject+"->";
			}
			if (!freezeClip.visible) {
					if (SiteManager.VERBOSE) Area80.log(callerObject + "Duplicate unFreeze(); Command", this);
					return;
			}
			if(SiteManager.VERBOSE) Area80.log(callerObject + "unFreeze()", this);
			freezeClip.visible = false;
		}
		
		private function progressHandler (e:ProgressEvent):void {
				if(pageProgressDict[e.target]) IProgressClip(pageProgressDict[e.target]).updateProgress(e.bytesLoaded, e.bytesTotal);
		}
		
		private function onDisplayAdded (e:Event):void {
				if (e.target.parent == _main) {
					if(SiteManager.VERBOSE) Area80.log("Display Children ["+e.target+"] added to main", this);
					_main.setChildIndex(freezeClip, _main.numChildren - 1);
				}
		}
	}
	
}